#include "MVDataMB.h"
#include "MVDataSubMB.h"
#include <list>

CMVDataMB::CMVDataMB( TYPE_MB mb_type, int x, int y ) : CMVDataMBCommon()
{
	m_ix = x;
	m_iy = y;
	m_eMBType = mb_type;
	m_plstSubMB = new std::list<CMVDataSubMB*>();
}

CMVDataMB::CMVDataMB( const CMVDataMB & mb ) : CMVDataMBCommon( static_cast<const CMVDataMBCommon>( mb ) )
{
	m_ix = mb.m_ix;
	m_iy = mb.m_iy;
	m_eMBType = mb.m_eMBType;
	m_plstSubMB = new std::list<CMVDataSubMB*>();
	m_plstSubMB->assign( mb.m_plstSubMB->begin(), mb.m_plstSubMB->end() );
}

CMVDataMB::~CMVDataMB()
{
	delete m_plstSubMB;
}

int CMVDataMB::SetCoordinate( int x, int y )
{
	m_ix = x;
	m_iy = y;

	return 0;
}

int CMVDataMB::GetCoordinate( int& x, int& y ) const
{
	x = m_ix;
	y = m_iy;

	return 0;
}

int CMVDataMB::GetCoordinateX() const
{
	return m_ix;
}

int CMVDataMB::GetCoordinateY() const
{
	return m_iy;
}

int CMVDataMB::SetMBType( TYPE_MB mb_type )
{
	m_eMBType = mb_type;
	return 0;

}

TYPE_MB CMVDataMB::GetMBType() const
{
	return m_eMBType;
}

int CMVDataMB::AddSubMB(  const CMVDataSubMB * submb )
{
	
	CMVDataSubMB * old_sub_mb = _GetSubMBByLocation( submb->GetLoc() );
	if ( old_sub_mb == NULL )
	{
		// 以前这个位置上没有Sub MB， 直接加入
		CMVDataSubMB * sub_mb_new = new CMVDataSubMB( *submb );
		m_plstSubMB->push_back( sub_mb_new );
		// TODO 排序
	}
	else
	{
		// 要更新旧的Sub MB
		*old_sub_mb = *submb;
	}

	return 0;
}


bool CMVDataMB::HaveSubMB() const
{
	if ( m_plstSubMB->size() != 0 )
	{
		return true;
	}

	return false;
}

bool CMVDataMB::ShouldHaveSubMB() const
{
	// TODO CMVDataMB::ShouldHaveSubMB
	return true;
}

const CMVDataSubMB * CMVDataMB::GetSubMBByLocation( LOC_BLOCK mbloc ) const
{
	return _GetSubMBByLocation( mbloc );
}

CMVDataSubMB * CMVDataMB::_GetSubMBByLocation( LOC_BLOCK mbloc ) const
{

	if( m_plstSubMB->empty() )
	{
		return NULL;
	}

	std::list<CMVDataSubMB*>::iterator i = m_plstSubMB->begin();
	for( ; i != m_plstSubMB->end(); i++ )
	{
		if( (*i)->GetLoc() == mbloc )
		{
			return (*i);
		}

	}
	return NULL;

}

const CMVDataSubMB * CMVDataMB::GetNextSubMB( const CMVDataSubMB * curr_sub_mb ) const
{

	if ( m_plstSubMB->empty() )
	{
		return NULL;
	}

	if( NULL == curr_sub_mb )
	{
		return *(m_plstSubMB->begin());
	}

	std::list<CMVDataSubMB*>::iterator i = m_plstSubMB->begin();
	for( ; i != m_plstSubMB->end(); i++ )
	{
		if( (*i) == curr_sub_mb )
		{
			i++;
			if( i != m_plstSubMB->end() )
			{
				return (*i);
			}

			break;
		}

	}

	return NULL;

}

bool CMVDataMB::operator == ( const CMVDataMB& mb ) const
{
	if( this->m_ix == mb.m_ix && this->m_iy == mb.m_iy )
	{
		return true;
	}
	return false;

}

bool CMVDataMB::operator != ( const CMVDataMB& mb ) const
{
	if( this->m_ix == mb.m_ix && this->m_iy == mb.m_iy )
	{
		return false;
	}
	return true;

}

CMVDataMB& CMVDataMB::operator = ( const CMVDataMB& mb )
{
	static_cast<CMVDataMBCommon>(*this) = static_cast<CMVDataMBCommon>( mb );

	m_ix = mb.m_ix;
	m_iy = mb.m_iy;
	m_eMBType = mb.m_eMBType;

	m_plstSubMB->clear();
	m_plstSubMB->assign( mb.m_plstSubMB->begin(), mb.m_plstSubMB->end() );

	return *this;

}


int CMVDataMB::AddBlock( const CMVDataBlock * block )
{
	if ( !block->IsValid() )
	{
		return -1;
	}

	LOC_BLOCK first_layer_loc = block->GetFirstLayerLoc();
	LOC_BLOCK second_layer_loc = block->GetSecondLayerLoc();

	switch ( block->GetShape() )
	{
	// 这个Block是一个Macro Block
	case SHAPE_BLOCK_MB:
		{
			// 这个Macro block是否没有子SubMB
			if ( m_plstSubMB->size() != 0 )
			{
				// 要向一个有SubMB的MB上添加一个MB类型的Block，失败
				return -1;
			}
			else
			{
				//更新当前MB的属性
				if( block->HaveASAD() ) SetASAD( block->GetASAD() );
				if( block->HaveSADBitCount() ) SetSADBitCount( block->GetSADBitCount() );
				if( block->HaveMVCoordinate() ) SetMVCoordinate( block->GetMVCoordinateX(), block->GetMVCoordinateY() );
			}
		}

	// 这个Block是一个8x16或者16x8或者8x8的SubMB
	case SHAPE_BLOCK_SUB_MB:
		{
			CMVDataSubMB * pSubMBNew = new CMVDataSubMB();

			if( pSubMBNew->CopyDataFromBlock( block ) == 0 && AddSubMB( pSubMBNew ) == 0 )
			{
				delete pSubMBNew;
				return 0;
			}
			else
			{
				delete pSubMBNew;
				return -1;
			}
		}

	// 这个Block是一个SubSubMB
	case SHAPE_BLOCK_SUB_SUB_MB:
		{
			// 取得对应的SubMB指针
			CMVDataSubMB * pSubMBNew = NULL;
			const CMVDataSubMB * pSubMB = GetSubMBByLocation( first_layer_loc );
			if ( NULL == pSubMB )
			{
				pSubMBNew = new CMVDataSubMB();
				pSubMBNew->SetLoc( first_layer_loc );
				if ( second_layer_loc == LOC_BLOCK_DOWN || second_layer_loc == LOC_BLOCK_UP )
				{
					pSubMBNew->SetSubMBType( TYPE_SUB_MB_8x4 );
				}
				else if ( second_layer_loc == LOC_BLOCK_LEFT || second_layer_loc == LOC_BLOCK_RIGHT )
				{
					pSubMBNew->SetSubMBType( TYPE_SUB_MB_4x8 );
				}
				else if ( second_layer_loc == LOC_BLOCK_UPLEFT || second_layer_loc == LOC_BLOCK_UPRIGHT ||
						second_layer_loc == LOC_BLOCK_DOWNLEFT || second_layer_loc == LOC_BLOCK_DOWNRIGHT )
				{
					pSubMBNew->SetSubMBType( TYPE_SUB_MB_4x4 );
				}
				else
				{
					// TODO is there anyone else?
				}

			}
			else
			{
				pSubMBNew = new CMVDataSubMB( *pSubMB );
			}

			CMVDataSubSubMB * pSubSubMBNew = new CMVDataSubSubMB();
			if ( pSubSubMBNew->CopyDataFromBlock( block ) == 0 && pSubMBNew->AddSubSubMB( pSubSubMBNew ) == 0 )
			{
				delete pSubSubMBNew;
				AddSubMB( pSubMBNew );
				delete pSubMBNew;
				return 0;
			}
			else
			{
				delete pSubSubMBNew;
				delete pSubMBNew;
				return -1;
			}

		}

	default:
		return -1;

	}

	return 0;
}


const CMVDataBlock * CMVDataMB::GetNextBlock( const CMVDataBlock * curr_block ) const
{

	CMVDataBlock * pBlock = CMVDataBlock::CreateBlock();
	pBlock->SetMB( this );

	// 返回第一个 Block
	if ( NULL == curr_block )
	{
		const CMVDataSubMB * pSubMB = GetNextSubMB( NULL );
		if ( NULL == pSubMB )
		{
			// 没有Sub MB，表示只有这个MB块，返回自己
			pBlock->CopyDataFrom( this );
			pBlock->SetFirstLayerLoc( LOC_BLOCK_FULL );
			pBlock->SetSecondLayerLoc( LOC_BLOCK_NO_USE );
			return pBlock;
		}

		const CMVDataSubSubMB * pSubSubMB = pSubMB->GetNextSubSubMB( NULL );
		if ( NULL == pSubSubMB )
		{
			// 没有Sub Sub MB，表示这个Sub MB就是第一个块
			pBlock->CopyDataFrom( pSubMB );
			pBlock->SetFirstLayerLoc( pSubMB->GetLoc() );
			pBlock->SetSecondLayerLoc( LOC_BLOCK_FULL );
			return pBlock;
		}

		// 有SubSubMB， 要返回第一个
		pBlock->CopyDataFrom( pSubSubMB );
		pBlock->SetFirstLayerLoc( pSubMB->GetLoc() );
		pBlock->SetSecondLayerLoc( pSubSubMB->GetLoc() );
		return pBlock;
	}

	LOC_BLOCK first_layer_loc = curr_block->GetFirstLayerLoc();
	LOC_BLOCK second_layer_loc = curr_block->GetSecondLayerLoc();

	const CMVDataSubMB * pSubMB = NULL;


	// 当前Block是MB本身，没有下一个Block
	if( first_layer_loc == LOC_BLOCK_FULL )
	{
		return NULL;
	}

	pSubMB = GetSubMBByLocation( first_layer_loc );
	if( pSubMB == NULL )
	{
		return NULL;
	}
	else
	{

		if( second_layer_loc != LOC_BLOCK_FULL )
		{
			// 当前Block 不是Sub MB本身，要看其Sub Sub MB的位置
			const CMVDataSubSubMB * pSubSubMB = pSubMB->GetSubSubMBByLocation( second_layer_loc );

			if( pSubSubMB == NULL )
			{
				// 当前Block不存在，返回错误
				return NULL;
			}
			else
			{
				pSubSubMB = pSubMB->GetNextSubSubMB( pSubSubMB );

				if( pSubSubMB == NULL )
				{
					// 没有下一个Sub Sub MB了，要返回下一个Sub MB的第一个Sub Sub MB或者下一个Sub MB本身。
					// 方式同 second_layer_loc == LOC_BLOCK_FULL的情形
					// 转入 当前Block是Sub MB本身的处理方式
				}
				else
				{
					pBlock->CopyDataFrom( pSubSubMB );
					pBlock->SetFirstLayerLoc( pSubMB->GetLoc() );
					pBlock->SetSecondLayerLoc( pSubSubMB->GetLoc() );

					return pBlock;
				}

			}
		}
		

		// 当前Block是Sub MB本身，下一个Block是下一个Sub MB
		pSubMB = GetNextSubMB( pSubMB );

		if ( pSubMB == NULL )
		{
			// 没有下一个Sub MB
			return NULL;
		}
		else
		{
			// 有下一个Sub MB，如果它有Sub Sub MB，则取第一个，否则返回它本身
			const CMVDataSubSubMB * pSubSubMB = pSubMB->GetNextSubSubMB( NULL );
			
			// TODO: 能保证它就是没有Sub Sub MB吗？
			if ( pSubSubMB == NULL )
			{
				pBlock->CopyDataFrom( pSubMB );
				pBlock->SetFirstLayerLoc( pSubMB->GetLoc() );
				pBlock->SetSecondLayerLoc( LOC_BLOCK_FULL );
				
				return pBlock;
			}
			else
			{
				pBlock->CopyDataFrom( pSubSubMB );
				pBlock->SetFirstLayerLoc( pSubMB->GetLoc() );
				pBlock->SetSecondLayerLoc( pSubSubMB->GetLoc() );

				return pBlock;
			}

		}

	}
	return NULL;
}

const CMVDataBlock * CMVDataMB::GetBlockByLoc ( LOC_BLOCK first_layer_loc, LOC_BLOCK second_layer_loc ) const
{

	const CMVDataSubMB * pSubMB = NULL;

	CMVDataBlock * pBlock = CMVDataBlock::CreateBlock();
	pBlock->SetMB( this );
	pBlock->SetFirstLayerLoc( first_layer_loc );
	pBlock->SetSecondLayerLoc( second_layer_loc );

	pSubMB = GetSubMBByLocation( first_layer_loc );

	if ( pSubMB != NULL )
	{
		if( second_layer_loc == LOC_BLOCK_FULL )
		{
			pBlock->CopyDataFrom( pSubMB );
			return pBlock;
		}
		else
		{
			const CMVDataSubSubMB * pSubSubMB = NULL;
			pSubSubMB = pSubMB->GetSubSubMBByLocation( second_layer_loc );

			if( pSubSubMB != NULL )
			{
				pBlock->CopyDataFrom( pSubSubMB );
				return pBlock;
			}
			else
			{
				return NULL;
			}
		}
	}
	else
	{
		return NULL;
	}


	return NULL;
}

bool CMVDataMB::CheckBlockValidation() const
{
	// 0 1 2 3
	// 4 5 6 7
	// 8 9 A B
	// C D E F
	unsigned short block_bitmap = 0;

	if ( m_plstSubMB->size() == 0 )
	{
		return false;
	}

	const CMVDataSubMB * pSubMB = NULL;

	while( pSubMB = GetNextSubMB( pSubMB ) )
	{
		if( pSubMB->CheckValidation() )
		{
			if( (block_bitmap & LOC_BLOCK_BITMAP_IN_4X4[pSubMB->GetLoc()]) == 0 )
			{
				block_bitmap |= LOC_BLOCK_BITMAP_IN_4X4[pSubMB->GetLoc()];
			}
			else
			{
				return false;
			}

		}
		else
		{
			return false;
		}
	}

	if( block_bitmap == 0xFFFF )
	{
		return true;
	}
	else
	{
		return false;
	}
}